package no.ffi.gismoidm.pubsub;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * Holds a list of connected clients, and protects the critical regions
 * which result from overlapping insertions, deletions and traversals
 * @author anders
 */
public class ClientTable {
    private List<MessageClient> clients;
    private static ClientTable instance;
    private String myId;
    
    // Singleton pattern
    private ClientTable() {
        clients = new ArrayList();
        myId = MyCredentials.getInstance().getSubjectId();
    }

    public synchronized static ClientTable getInstance() { //TODO Synchronized?
        if (instance == null) instance = new ClientTable();
        return instance;
    }
    
    public int size() { return clients.size(); }
    
    // insert a client into the table
    public synchronized void addClient(MessageClient c) {
        // If there exists an entry with the same id, it must be terminated
        if (clients.contains(c)) {
            System.out.println("Duplicate clients, removing the oldest");
            removeClient(c);
        }
        clients.add(c);
    }
    
    public synchronized void removeClient(MessageClient c) {
        String idToRemove = c.getId();
        Iterator<MessageClient> it = clients.iterator();
        while (it.hasNext()) {
            MessageClient c1 = it.next();
            if (c1 == c) it.remove();
            //String idToCheck = c1.getId();
            //if (idToCheck.equals(idToRemove)) it.remove();
            return;
        } 
        // TODO loop termination could indicate an error condition
    }
    
    public synchronized List<MessageClient> matchPublication(Publication pub) {
        List<MessageClient> addressedClients = new ArrayList();
        Iterator<MessageClient> it = clients.iterator();
        while (it.hasNext()) {
            MessageClient c1 = it.next(); 
//            System.out.println("M="+c1.matchSubscriptions(pub));
            if (c1.matchSubscriptions(pub))
                addressedClients.add(c1);
        }
        return addressedClients;
    }
    
    public AggregateSubscription generateLocalAggSub() {
        List t = new ArrayList();
        // Iterate over client table and extract subscriptions
        Iterator<MessageClient> it = clients.iterator();
        while (it.hasNext()) {
            MessageClient m = it.next();
            t.addAll(m.getSubscriptions());
        }
        return new AggregateSubscription(t,myId);
    }
    
    public String getMyId() { return myId; }
}
